Pacote Shiny

André, Bruno, Caio, Gabriel e João Gabriel

Importando pacotes que serão utilizados para elaboração dos códigos

if(!require("pacman")) install.packages("pacman")
pacman::p_load("shiny",
               "tidyverse",
               "babynames",
               "DT",
               "shinythemes",
               "gapminder")

Sumário

  1. Introdução
  2. Estrutura Básica e Geral de um App Shiny
  3. Tipos de Inputs e Outputs
  4. Programação Reativa
  5. Tipos de Layout e Temas
  6. Dashboards no Shiny

Introdução

Funcionalidade

Shiny é um pacote do R (também disponível para o Python) que permite a criação e publicação de aplicações web sem necessidade de conhecimento prévio em HTML, CSS e JavaScript;

Ou seja, a proposta é facilitar a criação de apps web somente com conhecimento em R.

Estrutura Básica de um App Shiny

Em essência, um App Shiny é gerado a partir de dois objetos e a chamada de uma função:

  • UI (Interface do Usuário)

  • Server

  • Função shinyApp(ui, server)

library(shiny)

ui <- fluidPage(
  
)

server <- function(input, output) {
  
}

shinyApp(ui = ui, server = ui)

UI - Interface do Usuário

UI: Definição

O objeto UI é geralmente inicializado pela função fluidPage(), que gerá uma página HTML vazia (também podem ser usadas outras funções para inicializar o UI);

São definidos os tipos de inputs (valores de entrada) e outputs (valores de saída) que o App Shiny apresentará, assim como também a formatação, layout.

ui <- fluidPage(
  titlePanel("Aplicativo Teste"),
  sidebarLayout(
    sidebarPanel(
    ),
    mainPanel(
    )
  )
)

Tipos de Input

Estrutura Comum

Há inúmeros tipos de input disponíveis no Shiny.De todo modo, para que sejam reconhecidos e processados, todos ele precisam de dois parâmetros em comum:

  • Parâmetro “inputId”: Trata-se de uma string simples e única que será armazenada dentro da lista “input” que é parâmetro da função server(input, output). Desse modo, deve-se utilizar id´s diferentes para referenciar diferentes inputs;

  • Parâmetro “label”: Trata-se do rótulo/mensagem/instrução que irá aparecer no App Shiny, orientando o usuário sobre como ele deve interagir com as opções de input dadas.

selectInput(inputId = "input1",   # String identificadora do Input
            label = "Selecione uma das opções abaixo.",
            choices = c("A", "B", "C"))

sliderInput(inputId = "input2", # String identificadora do Input
            label = "Selecione um valor de interesse",
            value = 1925,
            min = 1900,
            max = 2000)

Tipos de Input

selectInput()

Dada uma listagem de opções fornecidas, é solicitado ao usuário selecionar uma ou algumas das opções dadas.

selectInput(inputId = 'input1',
            label = 'Escolha uma das opções',
            choices,
            selected = NULL,
            multiple = FALSE,
            ...)

Tipos de Input

checkboxGroupInput()

Semelhante à função selectInput(), mas com uma aparência levemente diferente, e permite selecionar, por padrão, múltiplas opções.

checkboxGroupInput(inputId,
              label,
              choices,
              selected = NULL,
              ...)

Tipos de Input

actionButton()

Pede ao usuário que aperte um botão interativo para que uma certa ação seja realizada no aplicativo.

actionButton(inputId = 'input1',
             label = 'Aperte o Botão para...',
             icon,
             width,
             ...)

Tipos de Input

sliderInput()

A partir de uma barra de rolagem (horizontal), o usuário é informado para selecionar um número dentro de um intervalo de valores estabelecido

sliderInput(inputId,
            label,
            min,
            max,
            value = "valor_default/padrao",
            ...)

Tipos de Input

textInput()

Trata-se de uma função para inserção de inputs em forma de texto.

textInput(inputId,
          label = "Informe seu nome",
          value = "Nome",
          width = NULL,
          placeholder = NULL)

Tipos de Input

passwordInput()

Semelhante a função tenxtInput(), com a diferença que o input informado aparecerá com tarjas (“*”)

passwordInput(input,
              label,
              value,
              width = NULL,
              placeholder = NULL)

Tipos de Input

Além das funções input citadas acima, há várias outras tais como:

dateInput(inputId,
          label,
          value = NULL,
          min = NULL,
          max = NULL,
          format = "yyyy-mm-dd",
          ...)
dateRangeInput(inputId,
               label,
               start = NULL,
               end = NULL,
               min = NULL,
               max = NULL,
               format = "yyyy-mm-dd",
               ...)
numericInput(inputId,
             label,
             value,
             min,
             max,
             step,
             width = NULL)
fileInput(inputId,
          label,
          multiple = FALSE,
          accept = NULL,
          width = NULL,
          ...)

Outputs

Tipos de Output

  • Os tipos de output são definidos no primeiro objeto, a UI (interface de usuário).

  • Assim como os inputs, no output também exigem uma identificação:

    • Parâmetro ‘outputId’.
datatable(outputId = "dataframe")   # Define um dataframe como output

htmlOutput(outputId = "html") # Define um documento HTML como output

imageOutput(outputId = 'image') # Define uma imagem como output

plotOutput(outputId = 'plot') # Define um gráfico como output

tableOutput(outputId = 'tabela') # Define uma tabela como output

textOutput(outputId = 'texto') # Define um texto como output
...

Tipos de Output

  • Feito isso, para que o(s) output(s) definido(s) seja(m) devidamente executado(s) e processado(s) pelo R, faz-se necessário também o uso das render functions (funções de renderização); por exemplo, “renderText({})”;

  • Estas são definidas no objeto Server (falaremos sobre logo a seguir).

ui3 <- fluidPage( 
  textInput("name", "Enter a name:"),
  textOutput("greeting")
)

server3 <- function(input, output, session){
  output$greeting <- renderText({
    paste("Do you prefer dogs or cats,", input$name, "?")
  })
}
  
shinyApp(ui = ui3, server = server3)

Server

Server

  • É nesse objeto que ocorre efetivamente a interação entre os inputs e outputs definidos no UI. Acessamos cada um dos inputs e outputs definidos usando o operador “$” em conjuto com os parâmetros input e/ou ouput do objeto server, ou seja:
    • input$input_id e output$output_id;

Estrutura Básica do Server

server <- function(input, output, session) {
  
  output$output_id
  
  input$input_id
  

}
  • Mas como exatamente cada elemento do parâmetro output pode interagir com um input?”

Server

Render Functions

  • Para que a interação entre input e output efetivamente ocorra, deve-se utilizar o que chamamos de “render functions”, que possuem variados tipos, e são escolhidas com base nos tipos de output que foram definidos no UI (tabela, gráfico, dataframe…).

As render functions (funções de renderização) são os objetos que irão efetivamente explicitar os outputs previamente definidos no UI;

server <- function(input, object) {
  output$output_id <- render**function**({
    
    "blackbox"(input$input_id) ## Dentro da render function, algum input armazenado dentro do parâmetro
                              # input como "input_id" recebe algum tipo de transformação de maneira a gerar
                              # um output
    })

}

Server

Render Functions

Alguns exemplos:

renderText({
  
})

renderPlot({
  
})

renderTable({
  
})

Elas possibilitam também a utilização de pacotes fora do pacote Shiny, mas que possuem suporte para renderizar seus resultados, como:

  • DT, PLotly e Leaflet

Exemplos de Render Functions

renderPlot()

server <- function(input, output, session){
  output$hist_waiting <- renderPlot({
    hist(faithful$waiting,
         breaks = input$nb_bins,
         col = 'steelblue')
  })
}

Exemplos de Render Functions

renderPlot() + pacote plotly

server <- function(input, output, session){
  # Função para plotar tendências de um nome
  plot_trends <- function(){
    babynames %>% 
      filter(name == input$name) %>% 
      plotly::plot_ly(, x = ~year, y = ~n, type = "bar")
  }
  output$plot_trendy_names <- plotly::renderPlotly(plot_trends())
}

Exemplos de Render Functions

renderTable() + pacote DT

server <- function(input, output){
  output$babynames_table <- DT::renderDT({
    babynames %>% 
      dplyr::slice_sample(prop = .1) %>% 
      DT::datatable()
  })
}

Tipos de Layout e Temas

Layout

Na estrutura básica os inputs são dispostos um embaixo do outro, visando melhorar a visualização do usuário, existem funções que alteram esse padrão:

  • titlePanel(): que implementa um título pro app:

  • sidebarLayout(): essa cria o layout geral de saída e que comporta opcções de disposição de inputs e outputs.

titlePanel()

Aqui a função tem como parametros apenas o label que está em formato de string

ui <- fluidPage(
  titlePanel("Histograma")
)

sidebarLayout()

No layout gerado por essa função divide-se a tela de saída em duas:

  • sidebarPanel(): aqui estarão as entradas do usário;

  • mainPanel(): nesta área são as saídas geradas no server.

inputPanel(
  titlePanel("Baby Name Explorer"),
  sidebarLayout(
    sidebarPanel(
      textInput('name', 'Enter Name', 'David')),
    mainPanel(  
      plotOutput('trend')))
)

Baby Name Explorer

sidebarPanel()

Neste espaço as opções de inputs vistas anteriormente são posicionadas no lado esquerdo da interface;

São possíveis envolopar mais de uma opção de input.

 inputPanel(
   titlePanel('BMI Calculator'),
   sidebarLayout(
     sidebarPanel(
       textInput('name', 'Enter your name'),
       numericInput('height', 'Enter height (in m)', 1.5, 1, 2, step = 0.1),
       numericInput('weight', 'Enter weight (in Kg)', 60, 45, 120),
       actionButton("show_bmi", "Show BMI")
     ),
     mainPanel()
    )
   )

BMI Calculator

mainPanel()

Nessa função vamos incluir as saídas que foram processadas no server e adicionadas no lado direito da interface;

Aqui caso haja uma saída basta apenas utilizar:

 ui <- fluidPage(
   titlePanel('BMI Calculator'),
   sidebarLayout(
     sidebarPanel(
       textInput('name', 'Enter your name'),
       numericInput('height', 'Enter height (in m)', 1.5, 1, 2, step = 0.1),
       numericInput('weight', 'Enter weight (in Kg)', 60, 45, 120),
       actionButton("show_bmi", "Show BMI")
     ),
     mainPanel(
       textOutput("bmi")
     )
   )
 )

tabsetPanel()

Caso existam mais de uma saída e deseja-se criar abas para exibir os resultados vamos usar essa função.

 ui <- fluidPage(
   titlePanel("UFO Sightings"),
   sidebarPanel(
     selectInput("state", "Choose a U.S. state:", choices = unique(usa_ufo_sightings$state)),
     dateRangeInput("dates", "Choose a date range:",
                    start = "1920-01-01",
                    end = "1950-01-01"
     )
   ),
   mainPanel(
     tabsetPanel(
       tabPanel("Plot", plotOutput("shapes")),
       tabPanel("Table", tableOutput("duration_table"))
     )
   )
 )

Dashboard

  • Uma das formas de se criar dashboards utilizando as funcionalidades do Shiny é utilizando o pacote shinydashboard
library(shinydashboard)

header <- dashboardHeader(title = "My first dashboard")

sidebar <- dashboardSidebar()

body <- dashboardBody()

ui <- dashboardPage(header, sidebar, body)

server <- function(input, output){
  
  shinyApp(ui, server)

Dashboard

  • Mudando parâmetros no header
  # Definindo novos parâmetros no header
  header <- dashboardHeader(title = "My first dashboard",
                            titleWidth = 300,
                            dropdownMenu(type = "messages"),
                            dropdownMenu(type = "notifications")
                            
  )
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • Mudando parâmetros na sidebar
# Definindo a sidebar e seus parâmetros
  sidebar <- dashboardSidebar(width = 300,
                              sidebarMenu(
                                id = "pages",
                                menuItem("Many charts", tabName = "charts",
                                         icon = icon("chart-line")),
                                menuItem("Statistics", tabName = "stats",
                                         icon = icon("file-excel"))
                              ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • É possível adicionar subtabs na sidebar
  # Adicionando subtabs na sidebar
  sidebar <- dashboardSidebar(
    width = 300,
    sidebarMenu(
      id = "pages",
      menuItem("Many charts", tabName = "charts",
               icon = icon("chart-line")),
      menuItem("Statistics", tabName = "stats",
               icon = icon("file-excel"),
               menuSubItem("Team 1", tabName = "team1",
                           icon = icon("user")))
    ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  shinyApp(ui, server)

Dashboard

  • Assim como adicionar inputs
# Adicionando inputs na sidebar
  
  sidebar <- dashboardSidebar(width = 300,
                              sidebarMenu(
                                id = "pages",
                                menuItem("Many charts", tabName = "charts",
                                         icon = icon("chart-line")),
                                menuItem("A couple of checkboxes",
                                         checkboxGroupInput("checkboxes",
                                                            "Days of the week",
                                                            choices = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")))
                              ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • Por fim é possível desativar a sidebar
  # Desativando a sidebar
  
  sidebar <- dashboardSidebar(disable = TRUE)
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Programação Reativa

O que é reatividade?

Resumidamente, reatividade em programação é o conceito que torna possível a interação dinâmcica do usuário com o programa, no qual o que é efetivamente executado e exibido se baseia no acompanhamento das mudanças de determinados valores. Por exemplo, se um determinado input muda, um novo cálculo deve ser executado e um novo output gerado.

Programação Reativa

Como funciona a reatividade em apps Shiny?

A reatividade se baseia em uma paradigma diferente de programção, chamado de declarativo. No Shiny, declaramos dentro da função server() quando e quais códigos devem ser executados a depender de cada nova situação. Podemos representar as relações de dependência entre input e output e os consequentes fluxos de execução nesses casos através de um diagrama de reatividade.

Programação Reativa

Diagrama de Reatividade

exemplo:

# ui
ui <- fluidPage(
  selectInput(
    inputId = "variavel_A",
    label = "Variável A",
    choices = variaveis
  ),
  plotOutput(outputId = "histograma_A"),
  selectInput(
    inputId = "variavel_B",
    label = "Variável B",
    choices = variaveis,
    selected = variaveis[2],
  ),
  plotOutput(outputId = "histograma_B")
)

Programação Reativa

Diagrama de Reatividade

exemplo:

# server
server <- function(input, output, session) {
  output$histograma_A <- renderPlot({
    print("Gerando histograma A...")
    hist(mtcars[[input$variavel_A]], main = "Histograma A")
  })
  output$histograma_B <- renderPlot({
    print("Gerando histograma B...")
    hist(mtcars[[input$variavel_B]], main = "Histograma B")
  })
}

# app
shinyApp(ui, server)

Programação Reativa

Diagrama de Reatividade

diagrama de reatividade do exemplo